#pragma once 

#include <iostream>
#include <functional>
#include <string>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include "logMessage.hpp"
#include "protocal.hpp"

#define BUF_NUM 1024

namespace tcps
{
    enum
    {
        USAGE = 1,
        SOCK_ERR,
        BIND_ERR,
        LISTEN_ERR  
    };

    using func_t = std::function<bool(const Request&, Response*)>;

    bool handlerEntry(int sock, func_t func)
    {
        char line[BUF_NUM];
        while(true)
        {
            //1、保证服务器收到一个请求
            std::string rq;
            std::string inbuffer;
            if(!recvTxt(sock, &rq, inbuffer))  
            {
                logMessage(NORMAL, "client quit");
                return true;
            }//2、将这个请求进行结构化，反序列化
            std::string content;
            if(!deLength(rq, &content))  return false;
            Request req;
            if(!req.deserialization(content))  return false;
            //3、然后对这个请求进行业务操作
            Response resp;
            func(req, &resp);

            //4、将得到结果转化成字节流，序列化
            std::string rsp;
            if(!resp.serialization(&rsp))  return false;
            std::string send_msg = enLength(rsp);
            if(send_msg.empty()) return false;

            //5、发送相应给客户端
            write(sock, send_msg.c_str(), send_msg.size());
        }
    }


    class TcpServer;

    const std::string gip = "0.0.0.0";

    class ThreadData
    {
    public:
        ThreadData(TcpServer* td, int sock)
        :_this(td), _sock(sock)
        {}
    public:
        TcpServer* _this;
        int _sock;
    };

    class CalServer
    {
    public:
        CalServer(const uint16_t & serverport )
        :_listensockfd(-1), _serverport(serverport) 
        {}
        void initCalServer()
        {
            _listensockfd = socket(AF_INET, SOCK_STREAM, 0);
            if(_listensockfd < 0)
            {
                logMessage(FATAL, "socket create error");
                exit(SOCK_ERR);
            }
            logMessage(NORMAL, "socket create success");
            struct sockaddr_in local;
            bzero(&local, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_serverport);
            local.sin_addr.s_addr = INADDR_ANY;

            if(bind(_listensockfd, (struct sockaddr*)&local, sizeof(local)) != 0)
            {
                logMessage(FATAL, "socket bind error");
                exit(BIND_ERR);
            }
            logMessage(NORMAL, "socket bind success");

            if(listen(_listensockfd, 4) != 0)
            {
                logMessage(FATAL, "socket listen error");
                exit(LISTEN_ERR);
            }
            logMessage(NORMAL, "socket listen success");
        }
        void runCalServer(func_t func)
        {
            signal(SIGCHLD, SIG_IGN);
            for(;;)
            {
                struct sockaddr_in client;
                socklen_t clientlen = sizeof(client);
                int sock = accept(_listensockfd, (struct sockaddr*)&client, &clientlen);
                if(sock < 0) 
                {
                    logMessage(ERROR, "socket accept error");
                    continue;
                }
                logMessage(NORMAL, "socket accept success: %d", sock);
                pid_t id = fork();
                if(id == 0)
                {
                    if(!handlerEntry(sock, func))
                    {
                        logMessage(ERROR, "request handler error");
                    }
                    close(sock);
                }
            }
        }
        ~CalServer()
        {
            close(_listensockfd);
        }
    private:
        std::string _serverip;
        uint16_t _serverport;
        int _listensockfd;
    };
}
